package com.aluka.nirvana.framework.core.configuration;

import com.aluka.nirvana.framework.core.handler.ControllerExceptionHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.commons.lang.SystemUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.Controller;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.MultipartConfigElement;
import java.util.Iterator;
import java.util.List;

/**
 * Nirvana Core Configuration
 * @author gongli
 * @since 2019/12/25
 */
@Configuration
@ComponentScan("com.aluka.nirvana")
@EnableConfigurationProperties(SwaggerConfiguration.class)
@EnableSwagger2
@EnableAutoConfiguration(excludeName = {
        "com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure",
        "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"}
)
public class NirvanaCoreConfiguration{

    @Autowired
    private SwaggerConfiguration swaggerConfiguration;

    @Bean
    @ConditionalOnMissingBean(MultipartConfigElement.class)
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxFileSize(104857600);
        factory.setLocation(SystemUtils.getJavaIoTmpDir().getPath());
        return factory.createMultipartConfig();
    }

    @Bean
    @ConditionalOnMissingBean(ControllerExceptionHandler.class)
    public ControllerExceptionHandler controllerExceptionHandler() {

        return new ControllerExceptionHandler();
    }
    @Bean
    public SwaggerConfiguration swaggerConfiguration() {
        return new SwaggerConfiguration();
    }

    @Configuration("WebMvcConfig")
    @ConditionalOnClass({Controller.class})
    public class WebMvcConfig implements WebMvcConfigurer {

        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
            Iterator converterIterator = converters.iterator();

            while(converterIterator.hasNext()) {
                HttpMessageConverter<?> converter = (HttpMessageConverter)converterIterator.next();
                if (converter instanceof MappingJackson2HttpMessageConverter) {
                    ObjectMapper om = ((MappingJackson2HttpMessageConverter)converter).getObjectMapper();
                    om.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
                }
            }
        }
    }

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
                .apis(RequestHandlerSelectors.basePackage(swaggerConfiguration.getBasePackage())).paths(PathSelectors.any()).build();
    }

    @Bean
    public ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(swaggerConfiguration.getTitle())
                .description(swaggerConfiguration.getDescription())
                .version(swaggerConfiguration.getVersion())
                .build();
    }

}
